package cn.ywang.config;

import cn.ywang.loadbalance.LoadBalance;
import cn.ywang.loadbalance.RandomLoadBalance;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.framework.recipes.cache.PathChildrenCache;
import org.apache.curator.framework.recipes.cache.PathChildrenCacheEvent;
import org.apache.curator.framework.recipes.cache.PathChildrenCacheListener;
import org.apache.curator.retry.ExponentialBackoffRetry;

import java.util.ArrayList;
import java.util.List;

/**
 * @Auther: BeatificWang
 * @Date: 2018/12/13 23:04
 */
public class ServiceDiscoverImp implements IServiceDiscover {
	List<String> repos = new ArrayList<>();

	private String serviceAddress;

	private CuratorFramework framework;

	public ServiceDiscoverImp(String serviceAddress) {
		this.serviceAddress = serviceAddress;
		this.framework = CuratorFrameworkFactory
				                 .builder()
				                 .connectString(serviceAddress)
				                 .sessionTimeoutMs(40000)
				                 .retryPolicy(new ExponentialBackoffRetry(3000, 10))
				                 .build();
		this.framework.start();
	}

	@Override
	public String discover(String serviceName, String version) {
		String servicePath = ZKConfig.REGISTRY_PATH + "/" + serviceName + "-" + version;
		try {
			this.repos = this.framework.getChildren().forPath(servicePath);
		} catch (Exception e) {
			throw new RuntimeException("获取子节点异常，" + e.getMessage(), e);
		}
		// 动态发现节点变化
		this.registerWatcher(servicePath);
		LoadBalance loadBalance = new RandomLoadBalance();
		return loadBalance.selectServer(this.repos);
	}

	private void registerWatcher(final String path) {
		PathChildrenCache childrenCache = new PathChildrenCache
				                                  (this.framework, path, true);
		PathChildrenCacheListener pathChildrenCacheListener = new PathChildrenCacheListener() {
			@Override
			public void childEvent(CuratorFramework curatorFramework, PathChildrenCacheEvent pathChildrenCacheEvent) throws Exception {
				ServiceDiscoverImp.this.repos = curatorFramework.getChildren().forPath(path);
			}
		};
		childrenCache.getListenable().addListener(pathChildrenCacheListener);
		try {
			childrenCache.start();
		} catch (Exception e) {
			throw new RuntimeException("注册PatchChild Watcher 异常" + e);
		}
	}
}
